<?php


require_once('./plugins/sfDoctrinePlugin/lib/doctrine/Doctrine/Task.php');

/**
 * Doctrine_Task_CompareDb
 *
 * @package     Doctrine
 * @subpackage  Task
 * @license     http://www.opensource.org/licenses/lgpl-license.php LGPL
 * @link        www.phpdoctrine.org
 * @since       1.0
 * @version     $Revision: 2761 $
 * @author      Frederico Carneiro <frederico.carneiro@gmail.com>
 */
class Doctrine_Task_CompareDb extends Doctrine_Task
{
    public $description          =   'Compare DB with models',
           $requiredArguments    =   array('models_path'     => 'Specify the path to your doctrine models folder.'),
           $optionalArguments    =   array();
    
    private $msg = "";
    private $errors = "";
    
    public function execute()
    {   
        // get models
		$models = Doctrine::filterInvalidModels(Doctrine::loadModels($this->getArgument('models_path')));
    	
    	//echo $this->getArgument('models_path');
		
    	$this->_verifyCaracterNumber(25);
    	  # comentado por enquanto pois o oracle não tem permissão para gravar.
    	  /**
    	   * @todo buscar o nome do schema no oracle para concatenar schema.tabela 
    	   * e comparar com o modelo. Deixar comentado o código atual para poder
    	   * no futuro usar os drivers do doctrine. 
    	   */ 
        $this->_compareDbWithModels($models);
        $this->_compareModelsWithDb($models);
        $this->_verifyFunction("segweb_fnde.criptografar");
        

        echo $this->errors;
    }
    
    /**
     * Compare tables and columns of the models with DB
     */
	private function _compareModelsWithDb($models) {
		$this->msg 		.=  "\n---------------- Model x DB -----------------\n\n";
		$this->errors 	.=  "\n---------------- Model x DB -----------------\n\n";
		
		foreach($models as $model) {
			// Get the table name
			$tableName = Doctrine::getTable($model)->getTableName();
			
			// test if exists a table in db with this name
        	if($this->_dbHasTable($tableName)) {
        		$this->msg .= "Table '".$tableName."' exists in DB\n";
        		
	        	foreach(Doctrine::getTable($model)->getColumnNames() as $column) {
	        		if($this->_dbHasColumn($tableName,$column)) {
	        			$this->msg .= "    Column '".$column."' exists in DB\n";
	        		} else {
	        			$this->msg .= "    Column '".$column."' doesn't exists in DB\n";
	        			$this->errors .= "\n    In Table ".$tableName.", Column '".$column."' doesn't exists in DB\n";
	        		}
	        	}
        		
        	} else {
        		$this->msg .= "Table '".$tableName."' doesn't exists in DB\n";
        		$this->errors .= "\n    Table '".$tableName."' doesn't exists in DB\n";
        	}
        	//$this->msg .= "\n";
        	//$this->errors .= "\n";
        	
        }
        $this->msg .= "\n---------------- Model x DB -----------------\n\n";
        //$this->errors .= "\n---------------- Model x DB -----------------\n\n";
    }
    
	/**
     * Compare tables and columns of the DB with models
     */
	private function _compareDbWithModels($models) {
		$this->msg .= "\n---------------- DB x Models -----------------\n\n";
		$this->errors .= "\n---------------- DB x Models -----------------\n\n";
		
		// Get List of Models
		//$models = Doctrine::filterInvalidModels(Doctrine::loadModels($this->getArgument('models_path')));
		
		// List the tables in DB
		foreach(Doctrine_Manager::connection()->import->listTables() as $tableName) {
			// test if exists a table in model with this name
        	if($table = $this->_ModelHasTable($tableName,$models)) {
        		$this->msg .= "Table '".$tableName."' exists in Model\n";
        		
        		// List of Columns in DB
        		foreach(Doctrine_Manager::connection()->import->listTableColumns($tableName) as $column) {
	        		// Test if exists a column in model with same name
        			if($this->_ModelHasColumn($table,$column['name'])) {
	        			$this->msg .= "    Column '".$column['name']."' exists in Model\n";
	        		} else {
	        			$this->msg .= "    Column '".$column['name']."' doesn't exists in Model\n";
	        			$this->errors .= "\n    In Table ".$tableName.", Column '".$column['name']."' doesn't exists in Model\n";
	        		}
	        	}
        		
        	} else {
        		$this->msg .= "Table '".$tableName."' doesn't exists in Model\n";
        		$this->errors .= "\n    Table '".$tableName."' doesn't exists in Model\n";
        	}
        	//$this->msg .= "\n";
        	//$this->errors .= "\n";
        	
        }
        $this->msg .= "\n---------------- DB x Models -----------------\n\n";
        //$this->errors .= "\n---------------- DB x Models -----------------\n\n";
    }

  private function addMsg($msg) {
    $this->msg .= $msg;
  }
  
  private function addError($err) {
    $this->msg .= $err;
    $this->errors .= $err;
  }
    /**
    * Verify if table name, column name and sequence name have a 
     * maximum number of caracteres.
     */
  private function _verifyCaracterNumber($num) {
    	$this->addError("\n---------------- Verify Number of Caracteres -----------------\n\n");
    	
        // List the tables.
    	foreach(Doctrine_Manager::connection()->import->listTables() as $table) {
    		if(strlen($table) > $num) {
    			$this->msg .= "Table '".$table."'(".strlen($table).") has an invalid number of caracteres (max = ".$num.").\n";
    			$this->errors .= "\n    Table '".$table."'(".strlen($table).") has an invalid number of caracteres (max = ".$num.").\n";
    		} else {
    			$this->addMsg("Table '".$table."'(".strlen($table).") is OK.\n");
    		}
    		
    		// List the columns of table.
    		foreach(Doctrine_Manager::connection()->import->listTableColumns($table) as $column) {
    			if(strlen($column['name']) > $num) {
	    			$this->msg .= "    Column '".$column['name']."'(".strlen($column['name']).") has an invalid number of caracteres (max = ".$num.").\n";
	    			$this->errors .= "\n    In Table ".$table.", Column '".$column['name']."'(".strlen($column['name']).") has an invalid number of caracteres (max = ".$num.").\n";
	    		} else {
	    			$this->msg .= "    Column '".$column['name']."'(".strlen($column['name']).") is OK.\n";
	    		}
    		}
    		//$this->msg .= "\n\n";
        	//$this->errors .= "\n\n";
    	}
    	
    	// List sequence of DB.
    	foreach(Doctrine_Manager::connection()->import->listSequences() as $sequence) {
    	if(strlen($sequence) > $num) {
    			$this->msg .= "\nSequence '".$sequence."'(".strlen($sequence).") has an invalid number of caracteres (max = ".$num.").\n";
    			$this->errors .= "\n    Sequence '".$sequence."'(".strlen($sequence).") has an invalid number of caracteres (max = ".$num.").\n";
    		} else {
    			$this->msg .= "\n    Sequence '".$sequence."'(".strlen($sequence).") is OK.\n";
    		}
    	}
    	
    	$this->msg .= "\n---------------- Verify Number of Caracteres -----------------\n\n";
        //$this->errors .= "\n---------------- Verify Number of Caracteres -----------------\n\n";
    }
    
    /**
     * Verify if the user has permission to access the  function
     */
  private function _verifyFunction($functionName) {
    	$this->msg .= "\n---------------- Verify Function ".$functionName."  -----------------\n\n";
    	$this->errors .= "\n------ Verify Function ".$functionName."  --------\n\n";
    	try {
	    	foreach(Doctrine_Manager::connection()->import->listFunctions() as $function) {
	    		if($functionName == $function) {
	    			$this->msg .= "Function ".$functionName." is OK.";
	    		} else {
	    			$this->msg .= "Function ".$functionName." was not accessed.";
	    			$this->errors .= "Function ".$functionName." was not accessed.";
	    		}
	    	}
	    	
    	} catch (Doctrine_Exception $e) {
    		$this->errors .= "\n    ".$e->getMessage()."\n";
    	}
    	$this->msg .= "\n---------------- Verify Function ".$functionName."  -----------------\n\n";
    }
    
    /**
     * Verifiy if DB has the table
     */
  private function _dbHasTable($tableName) {
    	// Get tables in DB
		foreach(Doctrine_Manager::connection()->import->listTables() as $table) {
			if($table == $tableName) {
				return true;
			}
		}
		return false;
    }
    
    /**
     * Verifiy if DB has the column
     */
	private function _dbHasColumn($tableName, $columnName) {
    	// Get columns of the table in DB
		foreach(Doctrine_Manager::connection()->import->listTableColumns($tableName) as $column) {
    		if(strtoupper($column['name']) == strtoupper($columnName)) {
	    		return true;
	    	}
    	}
		return false;
    }
    
    /**
     * Verifiy if Model has the table
     */
	private function _ModelHasTable($tableName,$models) {
		foreach($models as $model) {
			// Get the table name
			$table = Doctrine::getTable($model)->getTableName();
			if($table == $tableName) {
				// if exists, return the object Table
				return Doctrine::getTable($model); 
			}
		}
		return false;
    }
    
    /**
     * Verifiy if Model has the column
     */
	private function _ModelHasColumn($table, $columnName) {
    	// Get columns of the table in Model
		if($table->hasColumn($columnName)) {
	    	return true;
    	}
		return false;
    }
    
}